﻿using System.Diagnostics;

namespace Project1
{
	/// <summary>
	/// An abstract base classes for concrete search algorithm implementations.
	/// </summary>
	public abstract class AbstractSearch
	{
		private int expandedStates = 0;
		private long searchTimeInMilliseconds = 0;
		private int maxTreeSize = 0;

		/// <summary>
		/// This method should be called when a state is expanded so that the number of state expansions 
		/// can be tracked.
		/// </summary>
		protected void StateExpanded()
		{
			expandedStates++;
		}

		/// <summary>
		/// This method should be called when the size of the current search-tree changes. This makes it
		/// possible to keep track of the maximum search-tree size.
		/// </summary>
		/// <param name="size">The size of the search tree.</param>
		protected void SetCurrentTreeSize(int size)
		{
			if (size > maxTreeSize)
			{
				maxTreeSize = size;
			}
		}

		/// <summary>
		/// Gets the search time in milliseconds.
		/// </summary>
		public long SearchTimeInMilliseconds { get { return searchTimeInMilliseconds; } }

		/// <summary>
		/// Gets the maximum size of the search-tree.
		/// </summary>
		/// <value>
		/// The maximum size of the search-tree.
		/// </value>
		public int MaximumTreeSize { get { return maxTreeSize; } }

		/// <summary>
		/// Gets the number of states expanded during the search.
		/// </summary>
		public int ExpandedStates{ get { return expandedStates; } }

		/// <summary>
		/// Performs a search.
		/// </summary>
		/// <param name="problem">The search problem.</param>
		/// <returns>The goal state if a path leading to it can be found.</returns>
		public State Search(IProblem problem)
		{
			//
			// Reset all counters (performance metrics)
			//
			ResetCounters();
			//
			// Start a timer
			//
			Stopwatch watch = new Stopwatch();
			watch.Start();
			//
			// Perform the search
			//
			State result = PerformSearch(problem);
			//
			// Stop the timer and record the time elapsed
			//
			watch.Stop();
			searchTimeInMilliseconds = watch.ElapsedMilliseconds;
			//
			// Return the goal state (if any)
			//
			return result;
		}

		/// <summary>
		/// Resets the counters.
		/// </summary>
		protected void ResetCounters()
		{
			expandedStates = 0;
			maxTreeSize = 0;
		}

		/// <summary>
		/// Performs a search.
		/// </summary>
		/// <param name="problem">The search problem.</param>
		/// <returns>The goal state if found.</returns>
		protected abstract State PerformSearch(IProblem problem);
	}
}
